# 版本说明:  2024.11.23 新建
# 制作人员:  dzy
# 功能说明： 生成一个图.html , 这个是demo ,结合各种特性
# 备注说明： pyvis的版本为0.3.2
# 环境要求： python3/ windows32or64
# 设备要求：


# ---内置库---
import os
import sys
import time

# ---第三方库---
from colorama import init, Fore, Back, Style

import webbrowser
from pyvis.network import Network
from pyvis import __version__ as pyvis_ver

# ---自研库---
from mytools import getNowTime
from mytools import basicClass


'''
节点的名称用条目标题

节点的分组颜色用标签进行区分

边用链接, 读取[[]] 这个字符

定义组的作用, 定义组的颜色


'''


class Graph_Drawer(basicClass):
    def __init__(self):
        super().__init__()
        self.instanceName = 'Graph_drawer'
        print(pyvis_ver)
        assert pyvis_ver == '0.3.2', f'pyvis_ver==0.3.2 应该是 ,实际上为 {pyvis_ver}'
        # 创建一个空的网络图 有向图
        self.net = Network(directed=True, select_menu=True)
        self._add_node_counter = {'成功': 0, '失败': 0, '总计': 0, '名称': '节点添加_计算器'}
        self._add_edge_counter = {'成功': 0, '失败': 0, '总计': 0, '名称': '连线添加_计算器'}
        # 设置图的画布大小（宽度和高度）
        self.net.set_options("""
        var options = {
            "height": "800px",
            "width": "1250px",
            "physics": {
                "enabled": true
            }
        }
        """)

    def add_node1(self, n_id, lable, **kwagrs):
        """ 添加一个节点
             n_id (必选):节点的唯一标识符,自动转字符串,采用__str__ 或者__repr__
             label 节点的标签，通常会显示在节点旁边
             title 鼠标悬停在节点上时显示的提示文本
        Args:
            n_id (_type_): _description_
            lable (_type_): _description_


        Returns:
            _type_: _description_
        """
        try:
            # 主代码块
            actionName = '添加'
            actionValue = '节点'
            self._add_node_counter['总计'] += 1
            self.net.add_node(n_id=str(n_id), label=lable, **kwagrs)
        except Exception as e:
            # 异常时，执行该块
            msg_err = f'{actionName} {actionValue} 发生错误 {e}'
            self.classPrint(Fore.RED + msg_err)
            self._add_node_counter['失败'] += 1
            return False
        else:
            # 主代码块执行完，执行该块
            msg = f'{actionName} {actionValue} 执行正常'
            self.classPrint(Fore.GREEN + msg)
            self._add_node_counter['成功'] += 1
            return True

    def del_node1(self):  # TODO
        # 删除一个节点
        self.G = self.net.get_network_data()

        # 检查并删除没有边的节点
        nodes_to_remove = []
        for node in self.G.nodes:
            if len(list(self.G.neighbors(node))) == 0:  # 如果该节点没有任何邻居
                nodes_to_remove.append(node)

        # 使用 networkx 的 remove_node 删除这些没有边的节点
        for node in nodes_to_remove:
            self.G.remove_node(node)

        # 将更新后的 networkx 图重新设置到 pyvis 网络中
        self.net.from_nx(self.G)

    def add_edge1(self, node1, node2, **kwargs):
        # label: 在边的中间显示标签。
        # title: 鼠标悬停时显示的提示文本。

        # color: 设置边的颜色，支持颜色名称或十六进制代码（例如 "red" 或 "#FF0000"）。
        # width: 设置边的宽度，单位为像素。
        # arrows: 设置边的箭头类型，可以为 "to"、"from" 或 "middle"（表示箭头指向终点、起点或边的中间位置）。
        # physics: 设置边的物理效果，默认是 True，如果设置为 False，则边将固定不动。
        try:
            # 主代码块
            actionName = '添加'
            actionValue = '边'
            self._add_edge_counter['总计'] += 1
            self.net.add_edge(node1, node2, **kwargs)
        except Exception as e:
            # 异常时，执行该块
            msg_err = f'{actionName} {actionValue} 发生错误 {e}'
            self.classPrint(Fore.RED + msg_err)
            self._add_edge_counter['失败'] += 1
            return False
        else:
            # 主代码块执行完，执行该块
            msg = actionName + ' ' + actionValue + '执行正常'
            self.classPrint(Fore.GREEN + msg)
            self._add_edge_counter['成功'] += 1
            return True

    def draw(self):
        # 可视化网络图并生成 HTML 文件
        self.net.show("example.html", notebook=False)

        # 自动打开浏览器
        # webbrowser.open("file://" + os.path.abspath("example.html"))
    def statistics(self):  # TODO
        #
        self.classPrint(
            f'===统计=== : \n{self._add_node_counter} \n{self._add_edge_counter}')
        pass

    def __repr__(self):
        return f'<{self.instanceName}:remarks>'


if __name__ == '__main__':

    init(autoreset=1)
    wiki_drawer = Graph_Drawer()
    wiki_list = [
        ('secureCRT', 'tag工具'),
        ('DBeaver', 'tag工具'),
        ('selenium', 'tag工具'),
        ('自动化测试', 'tag测试'),
        ('web系统测试', 'tag测试'),
        ('app系统测试', 'tag测试'),
        ('ADB', 'tag系统'),
        ('工具', 'tag系统'),
        ('grass', 'tag系统'),
        ('rabbit', 'tag系统'),
        ('fox', 'tag系统'),
        ('cow', 'tag系统'),
        ('sheep', 'tag系统'),
        ('tiger', 'tag系统'),
        ('people', 'tag系统'),
        ('water', 'tag系统'),
        ('cat', 'tag系统'),
        ('fish', 'tag系统'),
    ]
    for iid, item in enumerate(wiki_list):
        wiki_drawer.add_node1(n_id=item[0], lable=item[0])
    wiki_drawer.add_edge1('工具', 'secureCRT')
    wiki_drawer.add_edge1('工具', 'DBeaver')
    wiki_drawer.add_edge1('工具', 'DBeaver')
    wiki_drawer.add_edge1('工具', 'selenium')
    wiki_drawer.add_edge1('工具', 'ADB')
    wiki_drawer.add_edge1('自动化测试', 'selenium')
    wiki_drawer.add_edge1('自动化测试', 'ADB')
    wiki_drawer.add_edge1('自动化测试', 'web系统测试')
    wiki_drawer.add_edge1('web系统测试', '自动化测试', label="边 1-2", title='可以放很多说明')
    wiki_drawer.add_edge1('自动化测试', 'app系统测试')
    wiki_drawer.add_edge1('自动化测试', 'pyautogui')
    wiki_drawer.add_edge1('selenium', 'web系统测试')
    wiki_drawer.add_edge1('rabbit', 'grass')
    wiki_drawer.add_edge1('grass', 'water')
    wiki_drawer.add_edge1('people', 'water')
    wiki_drawer.add_edge1('sheep', 'grass')
    wiki_drawer.add_edge1('cow', 'grass')
    wiki_drawer.add_edge1('fox', 'rabbit')
    wiki_drawer.add_edge1('tiger', 'fox')
    wiki_drawer.add_edge1('cat', 'fish')
    wiki_drawer.add_edge1('fish', 'water')
    wiki_drawer.add_edge1('tiger', 'ADB')
    wiki_drawer.statistics()
    wiki_drawer.draw()
